﻿using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Modules._2DoTasks.Components.Entities;
using DotNetNuke.Modules._2DoTasks.Components.ExceptionHandling;
using DotNetNuke.Modules._2DoTasks.Components.Interfaces;
using DotNetNuke.Modules._2DoTasks.Data;

namespace DotNetNuke.Modules._2DoTasks.Components.Controllers
{
    /// <summary>
    /// Controller object with business logic for ProjectMembers
    /// </summary>
    public class ProjectMemberController : IRepository<_ProjectMember, int>
    {
        private UnitOfWork _uof;
        private int _projectId;

        #region IRepository<_ProjectMember> Members

        public ProjectMemberController(UnitOfWork uof, int projectId)
        {
            _uof = uof;
            _projectId = projectId;
        }

        /// <summary>
        /// Gets the ProjectMember with the passed id
        /// </summary>
        /// <param name="userId">the user id</param>
        /// <param name="additionalFields">not used in ProjectMember entity</param>
        /// <returns>returns a ProjectMember object</returns>
        public _ProjectMember Get(int userId, params object[] additionalFields)
        {
            return CBO.FillObject<_ProjectMember>(DataProvider.Instance().GetProjectMember(userId, this._projectId, this._uof.CurrentUser.UserID));
        }

        /// <summary>
        /// Returns all ProjectMembers
        /// </summary>
        /// <returns>retuns list of ProjectMembers</returns>
        public List<_ProjectMember> GetAll()
        {
            return CBO.FillCollection<_ProjectMember>(DataProvider.Instance().GetAllProjectMembers(this._projectId, this._uof.CurrentUser.UserID));
        }

        /// <summary>
        /// Adds a new entity
        /// </summary>
        /// <param name="entity">entity to create</param>
        public void Add(_ProjectMember entity)
        {
            try
            {
                entity.ProjectId = _projectId;
                DataProvider.Instance().Add(entity, this._uof.CurrentUser.UserID);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("NOTMANAGER"))
                    throw new ProjectMemberValidationException("User is not Project Manager.", SharedEnum.CrudState.Insert, (int)InsertStatus.NOTMANAGER);

                if (exc.Message.Contains("pk_TDT_ProjectMembers"))
                    throw new ProjectMemberValidationException("User is already a member in the project.", SharedEnum.CrudState.Insert, (int)InsertStatus.UserAlreadyAMember);

                if (exc.Message.Contains("fk_PrjMbr_ProjectId"))
                    throw new ProjectMemberValidationException("Project not found.", SharedEnum.CrudState.Insert, (int)InsertStatus.ProjectNotFound);

                throw exc;
            }
        }

        /// <summary>
        /// Adds multiple project members
        /// </summary>
        /// <param name="entity">entity to create</param>
        public void AddMultiple(List<_ProjectMember> entities)
        {
            if (entities != null && entities.Any())
                DataProvider.Instance().AddMultiple(entities, this._uof.CurrentUser.UserID);
        }

        /// <summary>
        /// Updates a ProjectMember
        /// </summary>
        /// <param name="entity">ProjectMember to update</param>
        public void Update(_ProjectMember entity)
        {
            try
            {
                entity.ProjectId = _projectId;
                DataProvider.Instance().Update(entity, this._uof.CurrentUser.UserID);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("NOTMANAGER"))
                    throw new ProjectMemberValidationException("User is not Project Manager.",
                        SharedEnum.CrudState.Update, (int)UpdateStatus.NOTMANAGER);

                if (exc.Message.Contains("CANNOTCHANGEUSER"))
                    throw new ProjectMemberValidationException("User cannot change himself has a member.", SharedEnum.CrudState.Update, (int)UpdateStatus.CANNOTCHANGEUSER);

                if (exc.Message.Contains("CannotChangeOwner"))
                    throw new ProjectMemberValidationException("Owner data in members cannot be changed.", SharedEnum.CrudState.Update, (int)UpdateStatus.CannotChangeOwner);

                if (exc.Message.Contains("fk_PrjMbr_ProjectId"))
                    throw new ProjectMemberValidationException("Project not found.", SharedEnum.CrudState.Update, (int)UpdateStatus.ProjectNotFound);

                throw exc;
            }
        }

        /// <summary>
        /// Deletes an existing ProjectMember
        /// </summary>
        /// <param name="entity">ProjectMember to delete</param>
        public void Delete(_ProjectMember entity)
        {
            try
            {
                entity.ProjectId = _projectId;
                DataProvider.Instance().Delete(entity, this._uof.CurrentUser.UserID);
            }
            catch (SqlException exc)
            {
                if (exc.Message.Contains("NOTMANAGER"))
                    throw new ProjectMemberValidationException("User is not Project Manager.",
                        SharedEnum.CrudState.Delete, (int)DeleteStatus.NOTMANAGER);

                if (exc.Message.Contains("CANNOTDELETEUSER"))
                    throw new ProjectMemberValidationException("User cannot change himself has a member.",
                        SharedEnum.CrudState.Delete, (int)DeleteStatus.CANNOTDELETEUSER);

                if (exc.Message.Contains("CannotDeleteOwner"))
                    throw new ProjectMemberValidationException("Owner data in members cannot be changed.",
                        SharedEnum.CrudState.Delete, (int)DeleteStatus.CannotDeleteOwner);

                if (exc.Message.Contains("USERINTASK"))
                    throw new ProjectMemberValidationException("User associated to a project task.",
                        SharedEnum.CrudState.Delete, (int)DeleteStatus.USERINTASK);

                throw exc;
            }
        }

        /// <summary>
        /// Deletes an multiple ProjectMembers
        /// </summary>
        /// <param name="entity">ProjectMembers to delete</param>
        public void DeleteMultiple(List<_ProjectMember> entities)
        {
            if (entities != null && entities.Any())
                DataProvider.Instance().DeleteMultiple(entities, this._uof.CurrentUser.UserID);
        }

        /// <summary>
        /// Evaluates if the current logged user is a manager in the project id passed
        /// </summary>
        /// <param name="projectId">project to evaluate</param>
        /// <returns>returns true if a manager false otherwise</returns>
        public bool isCurrentUserManager()
        {
            return DataProvider.Instance().IsProjectManager(this._uof.CurrentUser.UserID, this._projectId);
        }

        #endregion IRepository<_ProjectMember> Members

        #region "Crud Enums"

        public enum InsertStatus
        {
            UserAlreadyAMember = -1,
            ProjectNotFound = -2,
            NOTMANAGER = -3
        }

        public enum UpdateStatus
        {
            CannotChangeOwner = -1,
            ProjectNotFound = -2,
            NOTMANAGER = -3,
            CANNOTCHANGEUSER = -4
        }

        public enum DeleteStatus
        {
            CannotDeleteOwner = -1,
            NOTMANAGER = -2,
            CANNOTDELETEUSER = -3,
            USERINTASK = -4
        }

        #endregion "Crud Enums"
    }
}